package com.ipemon.server;

import java.io.IOException;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.List;

import com.ipemon.exception.DataNotSentException;
import com.ipemon.exception.ProtocolDisRespectException;
import com.ipemon.model.Dresseur;
import com.ipemon.model.IPemon;
import com.ipemon.model.Logger;

public class DresseurUDP implements CallBack, Runnable{
	private PseudoTCPoverUDP connection = null;
	private Dresseur player = null;
	private CallBack callback = null;
	
	private boolean dataIn = false;
	private List<String> data = null;

	private Thread playerListeningThread = null;
	
	private boolean replyForDuelInitReceived = false;
	private boolean replyForNouveauIPemonReceived = false;
	
	
	public DresseurUDP(Dresseur player, CallBack callback) throws SocketException {
		this.player = player;
		this.callback = callback;
		connection = PseudoTCPoverUDP.getInstance();
		playerListeningThread = new Thread(this, "Player Listening Thread");
		playerListeningThread.start();
		
	}
	
	public synchronized IPemon getIPemonFromForet(String foretAddress, 
			int portNumber) throws ProtocolDisRespectException, UnknownHostException {
		
		String strGetNewIPemon = "NOUVEAU " + player.getIdentifiant();
		
		try {
			connection.sendData(InetAddress.getByName(foretAddress), portNumber, strGetNewIPemon);
			
			while(!replyForNouveauIPemonReceived)
				wait();
			
		} catch (IOException e) {
			e.printStackTrace();
		} catch (DataNotSentException e) {
			e.printStackTrace();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		
		String protocol[] = data.get(0).split(" ");

		IPemon ipemon;
		
		if(protocol[0].equalsIgnoreCase("donne")) {
			String newipemonString = protocol[1];
			
			ipemon = IPemon.getIPemonByDataStream(newipemonString);
			
		} else {
			throw new ProtocolDisRespectException(this, "NOUVEAU " + player.getIdentifiant());
		}

		dataIn = false;
		data = null;
		
		return ipemon;
	}
	
	public synchronized String connectToAnotherDresseur(String playerAddress, 
			int portNumber) throws ProtocolDisRespectException, UnknownHostException {
		
		String strStartChallenge = "DUEL_INIT " + player.getIdentifiant() + " 1" ;
		
		try {
			connection.sendData(InetAddress.getByName(playerAddress), portNumber, strStartChallenge);
			
			replyForDuelInitReceived = false;
			
			while(!replyForDuelInitReceived)
				wait();
			
		} catch (IOException e) {
			e.printStackTrace();
		} catch (DataNotSentException e) {
			e.printStackTrace();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		
		String protocol[] = data.get(0).split(" ");
		
		String newplayer = "";

		if(protocol[0].equalsIgnoreCase("DUEL_OK")) {
			try {
				newplayer = protocol[1] + " - " + protocol[2];
				
			} catch (IndexOutOfBoundsException exp) {
				throw new ProtocolDisRespectException(this, "DUEL_OK ");
			}
			
		} else {
			throw new ProtocolDisRespectException(this, "DUEL_OK ");
		}
		
		replyForDuelInitReceived = false;
		
		return newplayer;
	}

	
	public void startCombat() {
		
	}
	
	private synchronized void listen() {
		
		try {
			connection.receiveData(this);
			
			while(!dataIn)
				wait();
			
			treatListenedData();
			
		} catch (IOException e) {
			e.printStackTrace();
		} catch (InterruptedException e) {
			e.printStackTrace();
		} catch (ProtocolDisRespectException e) {
			e.printStackTrace();
		}
		
		listen();
	}

	public void treatListenedData() throws ProtocolDisRespectException {
		
		String protocolStr[] = data.get(0).split(" ");
		
		if(protocolStr[0].contains("DONNE")) {
			replyForNouveauIPemonReceived = true;
			notifyAll();
		}
		
		else if(protocolStr[0].contains("DUEL_INIT")) {
			callback.callIfReceived(CallBack.COMBAT, protocolStr[1]);
		} 
		
		else if (protocolStr[0].contains("DUEL_OK")) {
			replyForDuelInitReceived = true;
			this.notifyAll();
		} 
		
		else if (protocolStr[0].contains("ATTAQUE")) {
			
		}
		
		else if (protocolStr[0].contains("ISSUE")) {
			
		}
		
		else {
			throw new ProtocolDisRespectException(this, protocolStr[0]);
		}
		
		dataIn = false;
	}
	
	
	@Override
	public synchronized void callIfReceived(int type, Object data) {
		this.data = (List<String>) data;
		dataIn = true;
		this.notifyAll();
		return;
	}
	
	@Override
	public void run() {
		listen();
	}

	
	public static void main(String[] args) throws SocketException{
		
		DresseurUDP test = new DresseurUDP(new Dresseur("player"), null);
		
		try {
			
/*			String newPlayer = test.connectToAnotherDresseur("localhost", 9000);
			System.out.println(newPlayer);
*/
			IPemon ipemon = test.getIPemonFromForet("localhost", 9000);
			System.out.println(ipemon);
			
		} catch (ProtocolDisRespectException e) {
			e.printStackTrace();
		} catch (UnknownHostException e) {
			System.out.println("output sud be out");
		}

		Logger.getInstance().printLogs();
		
	}


	
	

}
